package de.fhaugsburg.games.boardgames.connect4;

import de.fhaugsburg.games.boardgames.*;
import de.fhaugsburg.games.boardgames.scrabble.scrabbleboard.IPiece;

public class Connect4Board extends Board<IPiece,Object>{
	
	private int[] colPieces;
	
	
	/**
	 * Constructor
	 * @param rows
	 * @param colums
	 */
	public Connect4Board(int rows, int colums) {
		super(rows, colums);
		colPieces = new int[rows];
		reset();				//also inits the height of played columns = 0
	}


	
	/**
	 * resets the board, also used as init
	 */
	@Override
	public void reset(){
		super.reset();
		for (int i = 0; i < this.getWidth(); i++) {
			colPieces[i] = 0;
		}
	}
	
	
	/**
	 * checks if move is on board and column is not already filled
	 * @param column
	 * @return
	 */
	public boolean isMoveValid(int column) {
		if (column > getWidth() || column < 0){
			return false;
		}else{
			int row = colPieces[column];			//how many pieces are in one column?
			return isOnTheBoard(row, column);
		}
	}

	
	/**
	 * throws one piece in a given column, as long as it is not already filled to the top
	 * Warning: superclass also provides a putPiece()-method with different signature
	 * @param piece
	 * @param column
	 */
	public void putPiece(BinaryPiece piece, int column) {
		if (isMoveValid(column)){
			int row = colPieces[column]++;		//put new piece on to of a column and increment
			super.putPiece(piece, row, column);
		}
	}
	
	
	
	/**
	 * return row-height of given column
	 * @param column
	 * @return
	 */
	public int getRowOfColumn(int column){
		return colPieces[column];
	}
	
	
	
	/**
	 * checks if given column has enough space for another piece, mostly used by robot algorithms
	 * @param column
	 * @return
	 */
	public boolean checkColFree(int column){
		return (getRowOfColumn(column) < getHeight());
	}
	
		
	
	/**
	 * this is the magic method to count the pieces next to each other
	 * @param row
	 * @param column
	 * @param piece
	 * @param dirVec consists of index 0 and 1, values between -1 and 1 or pieces are missed
	 * @return
	 */
	public int countEqualPiecesInOneDirection(int row, int column, BinaryPiece piece, int[] dirVec) {
		int directioncount = 0;
		if (dirVec[0] == 0 && dirVec[1] == 0) return 0;			//avoid infinite loop

		while (isOnTheBoard(row, column) && (piece == getPiece(row, column))){
			directioncount++;
			//increase/decrease rows/columns by given vector
			row += dirVec[0];
			column += dirVec[1];
		}
		//System.err.println("current: " +  "/" + column + " vector: " + dirVec[0 ]+ "/" + dirVec[1] + ": " + directioncount);
		return directioncount;
	}
	
	
	/**
	 * search in both directions by inverting the direction vector
	 * @param row
	 * @param column
	 * @param piece
	 * @param dirVec
	 * @return
	 */
	public int countEqualPiecesInTwoDirections(int row, int column, BinaryPiece piece, int[] dirVec) {
		int linecount = countEqualPiecesInOneDirection(row, column, piece, dirVec);
		//for (int i : dirVec) dirVec[i] = -dirVec[i];			//invert direction vector
		for (int i = 0; i < dirVec.length; i++) {
			dirVec[i] = -dirVec[i];
		}
		linecount += countEqualPiecesInOneDirection(row, column, piece, dirVec) -1;
		return linecount;
	}
	
	
	
	
	/**
	 * returns the highest number of pieces in any direction
	 * @param column
	 * @param piece
	 * @return
	 */
	public int countEqualPiecesInARow(int column, BinaryPiece piece){
		int[] dirVector = new int[]{0,0};
		int oneRowCount = 0;
		int directionCount = 0;
		int currentRow = getRowOfColumn(column) -1;
		if (currentRow >= 0){
			// FIXME: too many cycles, may be optimized
			for (int i = -1; i <= 1; i++) {
				dirVector[0] = i;
				for (int j = -1; j <= 1; j++) {
					dirVector[1] = j;
					directionCount = countEqualPiecesInTwoDirections(currentRow, column, piece, dirVector);
					if (directionCount > oneRowCount) oneRowCount = directionCount;
//					System.err.println("current: " + currentRow + "/" + column + " vector: " + dirVector[0 ]+ "/" + dirVector[1] + ": " + directionCount);
				}
			}
		}
		return oneRowCount;
	}
	
	
	
	/**
	 * can't move pieces in connect4 
	 */
	@Override
	public void movePiece(int fromRow, int fromColumn, int toRow, int toColumn) {
		throw new UnsupportedOperationException();
	}
}